package com.example.order.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.api.ResultUtil;
import com.example.common.filter.ReactiveRequestContextHolder;
import com.example.common.util.GsonUtil;
import com.example.feign.user.GoodsFeignClient;
import com.example.feign.user.UserFeignClient;
import com.example.order.mapper.OrderMapper;
import com.example.order.model.dto.ConfirmOrderDTO;
import com.example.order.model.dto.OrderItemDTO;
import com.example.order.model.po.OrderPO;
import com.example.order.model.vo.OrderVO;
import com.example.order.model.vo.PreOrderVO;
import com.example.order.service.ICartService;
import com.example.order.service.IOrderService;
import com.example.common.enums.BusinessTypeEnum;
import com.example.common.util.BusinessNoGenerator;
import com.example.redis.util.RedisUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ExecutionException;

@Service
@Slf4j
public class OrderService extends ServiceImpl<OrderMapper, OrderPO> implements IOrderService {

    private final String ORDER_TOKEN_PREFIX = "order:no:";

    /**
     * 释放锁lua脚本
     */
    private final String RELEASE_LOCK_LUA_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return '' end";

    @Resource
    private UserFeignClient userFeignClient;

    @Resource
    private GoodsFeignClient goodsFeignClient;

    @Resource
    private ThreadPoolTaskExecutor poolTaskExecutor;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private ICartService cartService;

    @Override
    public Mono<ResultUtil> confirmOrder(PreOrderVO preOrderVO) {
        ConfirmOrderDTO confirmOrderDTO = ConfirmOrderDTO.builder().build();
        log.info("confirm order begin, param: {}", preOrderVO.toString());
        if (preOrderVO.getId() != null){
            // 直接购买
            ResultUtil goodsResult = goodsFeignClient.getGoodsById(preOrderVO.getId());
            if (goodsResult.getCode() == 200){
                if (goodsResult.getData() == null){
                    log.info("confirm order, get goods info empty");
                    return Mono.just(ResultUtil.failed("通过ID获取商品为空"));
                }
                Map<String, Object> map = GsonUtil.toMap(goodsResult.getData());
                OrderItemDTO orderItemDTO = GsonUtil.toObject(map, OrderItemDTO.class);
                confirmOrderDTO.getOrderList().add(orderItemDTO);
            }else{
                log.error("confirm order, get goods info error");
                return Mono.just(ResultUtil.failed("通过ID获取商品为错误"));
            }
        }else {
            // 购物车购买
            Mono<ResultUtil> mono = cartService.getCartById();
            mono.flatMap(resultUtil -> Mono.just(resultUtil.getData())).subscribe(s->{
                log.info("===========================");
                log.info(s.toString());
            });
        }

//        userFeignClient.getAddressByUserId()

        // 生成一个订单号，放到redis中，用于防止订单的重复提交
        String orderNo = BusinessNoGenerator.generate(BusinessTypeEnum.ORDER);
        confirmOrderDTO.setOrderToken(orderNo);
        redisUtil.set(ORDER_TOKEN_PREFIX + orderNo, orderNo);

        return Mono.just(ResultUtil.success(confirmOrderDTO));
    }

    @Override
    public Mono<ResultUtil> createOrder(OrderVO orderVO) throws ExecutionException, InterruptedException {
        log.info("create order begin, param: {}", orderVO.toString());

        log.info("order no is {}", orderVO.getOrderNum());
        // 订单重复提交校验
        String orderNo = orderVO.getOrderNum();
        DefaultRedisScript<String> redisScript = new DefaultRedisScript<>(RELEASE_LOCK_LUA_SCRIPT, String.class);
        String execute = redisUtil.execute(redisScript, Collections.singletonList(ORDER_TOKEN_PREFIX + orderNo), orderNo);
        Assert.isTrue("".equals(execute), "订单不可重复提交");

        // 判断是否购买商品
        Long goodsId = orderVO.getGoodsId();
        Assert.isTrue(goodsId == null, "订单商品不能为空");


        OrderPO orderPO = new OrderPO();
        BeanUtils.copyProperties(orderVO, orderPO);

        // 根据地址id获取
        ResultUtil monoAddress = poolTaskExecutor.submit(()->userFeignClient.getAddressById(orderVO.getAddressId())).get();

        Mono<Long> requestMono = ReactiveRequestContextHolder.getUserId();

        return requestMono.flatMap(userId -> {

            return Mono.just(monoAddress);
        });
    }

}
